﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using UBCon.Ribbon.Interfaces;
using UBCon.Ribbon.Models;

namespace UBCon.Ribbon
{
    internal partial class RibbonTabItemPanel : Panel, IScrollInfo, IRibbonControl
    {
        #region Constructors

        /// <summary>
        /// Initializes a new instance of the UBCon.Ribbon.RibbonTabItemPanel class.
        /// </summary>
        public RibbonTabItemPanel()
        {
            _translate = new TranslateTransform();

            RenderTransform = this._translate;

        }
        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets a boolean value which indicates whether panel is animated on scroll.
        /// </summary>
        [Bindable(true),
        Browsable(true),
        Category("Behavior"),
        ReadOnly(false)]
        public bool AnimatedScroll
        {
            get { return (bool)GetValue(AnimatedScrollProperty); }
            set { SetValue(AnimatedScrollProperty, value); }
        }

        // Using a DependencyProperty as the backing store for AnimatedScroll.  This enables animation, styling, binding, etc...
        public static readonly System.Windows.DependencyProperty AnimatedScrollProperty =
            DependencyProperty.Register("AnimatedScroll", typeof(bool), typeof(RibbonTabItemPanel), 
            new PropertyMetadata(true));

        [Bindable(true),
        Browsable(true),
        Category("Behavior"),
        ReadOnly(false)]
        public double ScrollBy
        {
            get { return (double)GetValue(ScrollByProperty); }
            set { SetValue(ScrollByProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ScrollBy.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ScrollByProperty =
            DependencyProperty.Register("ScrollBy", typeof(double), typeof(RibbonTabItemPanel), new PropertyMetadata(10.0D));


        /// <summary>
        /// Gets or sets panel's orientation.
        /// </summary>
        [Bindable(true),
        Browsable(true),
        Category("Behavior"),
        ReadOnly(false)]
        public System.Windows.Controls.Orientation Orientation
        {
            get { return (System.Windows.Controls.Orientation)GetValue(OrientationProperty); }
            set { SetValue(OrientationProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Orientation.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty OrientationProperty =
            DependencyProperty.Register("Orientation", typeof(Orientation), typeof(RibbonTabItemPanel), new 
                PropertyMetadata(Orientation.Vertical));

        [Bindable(true),
        Browsable(true),
        Category("Behavior"),
        ReadOnly(false)]
        public bool FitsToViewport
        {
            get { return (bool)GetValue(FitsToViewportProperty); }
            set { SetValue(FitsToViewportProperty, value); }
        }

        // Using a DependencyProperty as the backing store for FitsToViewport.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty FitsToViewportProperty =
            DependencyProperty.Register("FitsToViewport", typeof(bool), typeof(RibbonTabItemPanel), 
            new PropertyMetadata(false));

        /// <summary>
        /// Gets the value of the UBCon.Ribbon.RibbonStackPanel.RibbonTabItemModel attached property for the 
        /// given dependency object.
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="value"></param>
        internal static RibbonTabItemModel GetRibbonTabItemModel(DependencyObject obj)
        {
            return (RibbonTabItemModel)obj.GetValue(RibbonTabItemModelProperty);
        }

        /// <summary>
        /// Sets the value of the UBCon.Ribbon.RibbonStackPanel.RibbonTabItemModel attached property for the 
        /// given dependency object.
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="value"></param>
        internal static void SetRibbonTabItemModel(DependencyObject obj, RibbonTabItemModel value)
        {
            obj.SetValue(RibbonTabItemModelProperty, value);
        }

        /// <summary>
        /// Identifies UBCon.Ribbon.RibbonStackPanel.RibbonTabItemModel attached property.
        /// </summary>
        internal static readonly DependencyProperty RibbonTabItemModelProperty =
            DependencyProperty.RegisterAttached("RibbonTabItemModel", typeof(RibbonTabItemModel), typeof(RibbonTabItemPanel));


        /// <summary>
        /// Gets the value of the UBCon.Ribbon.RibbonStackPanel.ContextualTabItemsGroupModel attached property for the 
        /// given dependency object.
        /// </summary>
        /// <param name="obj"></param>
        internal static ContextualTabItemsGroupModel GetContextualTabItemsGroupModel(DependencyObject obj)
        {
            return (ContextualTabItemsGroupModel)obj.GetValue(ContextualTabItemsGroupModelProperty);
        }

        /// <summary>
        /// Sets the value of the UBCon.Ribbon.RibbonStackPanel.ContextualTabItemsGroupModel attached property for the 
        /// given dependency object.
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="value"></param>
        internal static void SetContextualTabItemsGroupModel(DependencyObject obj, ContextualTabItemsGroupModel value)
        {
            obj.SetValue(ContextualTabItemsGroupModelProperty, value);
            
        }

        /// <summary>
        /// Identifies UBCon.Ribbon.RibbonStackPanel.ContextualTabItemsGroupModel attached property.
        /// </summary>
        internal static readonly DependencyProperty ContextualTabItemsGroupModelProperty =
            DependencyProperty.RegisterAttached("ContextualTabItemsGroupModel", typeof(ContextualTabItemsGroupModel),
            typeof(RibbonTabItemPanel));

        
        #endregion

        #region Depenency Property Changed Callbacks
        
        #endregion

        #region Overrides
        
        /// <summary>
        /// Invalidates the measurement state (layout) for the element. (Inherited from UIElement.)
        /// </summary>
        /// <param name="availableSize">The available size that this element can give to child elements. 
        /// Infinity can be specified as a value to indicate that the element will size to whatever content is available.</param>
        /// <returns>The size that this element determines it needs during layout, based on its calculations of child element sizes.</returns>
        protected override Size MeasureOverride(Size availableSize)
        {
            double w = 0, mSize = 0;

            if (Orientation == System.Windows.Controls.Orientation.Horizontal)
            {
                foreach (UIElement item in InternalChildren)
                {
                    item.Measure(infiniteSize);

                    w += item.DesiredSize.Width;

                    mSize = Math.Max(mSize, item.DesiredSize.Height);
                }
                if (double.IsPositiveInfinity(availableSize.Width))
                {
                    measureSize.Width = w;
                    //size.Width = w;
                }
                else
                {
                    if (!FitsToViewport)
                    {
                        measureSize.Width = Math.Min(availableSize.Width, w); 
                        //size.Width = Math.Min(availableSize.Width, w);
                    }
                    else
                    {
                        measureSize.Width = availableSize.Width;
                        //size.Width = availableSize.Width;
                    }
                }
                measureSize.Height = mSize;
                //size.Height = GetMaxHeight();
            }
            else
            {
                foreach (UIElement item in InternalChildren)
                {
                    item.Measure(infiniteSize);

                    w += item.DesiredSize.Height;
                    
                    mSize = Math.Max(mSize, item.DesiredSize.Width);
                }
                if (double.IsPositiveInfinity(availableSize.Height))
                {
                    measureSize.Height = w;
                    //size.Height = w;
                }
                else
                {
                    measureSize.Height = Math.Min(availableSize.Height, w);
                    //size.Height = Math.Min(availableSize.Height, w);
                }
                measureSize.Width = mSize;
            }
            if (ScrollOwner != null)
            {
                UpdateScrollInfo(measureSize);
            }
            return measureSize;

        }

        /// <summary>
        /// Invalidates the arrange state (layout) for the element. 
        /// After the invalidation, the element will have its layout updated, which will occur 
        /// asynchronously unless subsequently forced by UpdateLayout. (Inherited from UIElement.)
        /// </summary>
        /// <param name="finalSize">The finalSize size that this element can give to child elements. 
        /// Infinity can be specified as a value to indicate that the element will size to whatever content is available.</param>
        /// <returns>The size that this element determines it needs during layout, based on its calculations of child element sizes.</returns>
        protected override Size ArrangeOverride(Size finalSize)
        {
            double x = 0, y = 0;
            int count = InternalChildren.Count;
            UIElement element=null;
            if (this.Orientation == System.Windows.Controls.Orientation.Horizontal)
            {
                for (int i = 0; i < count; i++)
                {
                    element = InternalChildren[i];

                    RibbonTabItemModel model = element.GetValue(RibbonTabItemPanel.RibbonTabItemModelProperty) as RibbonTabItemModel;
                  
                    if (model == null) 
                    {
                        model = new RibbonTabItemModel()
                        {
                            UIElement = element,
                            Index = i
                        };

                        element.SetValue(RibbonTabItemPanel.RibbonTabItemModelProperty, model);

                        TabItemModels.Add(model);
                    }

                    arrangeRect.Width = element.DesiredSize.Width;

                    arrangeRect.Height = !double.IsPositiveInfinity(finalSize.Height) ? Math.Max(element.DesiredSize.Height, finalSize.Height) : element.DesiredSize.Height;

                    if (model.XLocation != x)
                    {
                        model.XLocation = x;
                    }
                    if (model.YLocation != y)
                    {
                        model.YLocation = y;
                    }

                    arrangeRect.X = model.XLocation;

                    arrangeRect.Y = model.YLocation;

                    element.Arrange(arrangeRect);
                    
                    //Window window = Window.GetWindow(element);

                    Point wPos = element.TranslatePoint(emptyPoint, null);
                    model.WindowRelativePosX = wPos.X;
                    model.WindowRelativePosY = wPos.Y;

                    x += element.DesiredSize.Width;
                }
            }
            else
            {
                for (int i = 0; i < count; i++)
                {
                    RibbonTabItemModel model = (from m in TabItemModels where m.Index == i select m).FirstOrDefault();

                    if (model == null)
                    {
                        element = InternalChildren[i];

                        model = new RibbonTabItemModel()
                        {
                            UIElement = element,
                            Index = i
                        };

                       element.SetValue(RibbonTabItemPanel.RibbonTabItemModelProperty, model);

                      TabItemModels.Add(model);
                    }
                    
                    element = model.UIElement;

                   arrangeRect.Height = element.DesiredSize.Height;

                   arrangeRect.Width = !double.IsPositiveInfinity(finalSize.Width) ? Math.Max(element.DesiredSize.Width, finalSize.Width) : element.DesiredSize.Width;

                    if (model.XLocation != x)
                    {
                        model.XLocation = x;
                    }
                    arrangeRect.X = model.XLocation;

                    if (model.YLocation != y)
                    {
                        model.YLocation = y;
                    }

                    arrangeRect.Y = model.YLocation;

                    element.Arrange(arrangeRect);

                    y += element.DesiredSize.Height;
                }
            }

            return finalSize;
        }

        #endregion

        #region Methods

       
        #endregion

        #region Event Handlers

        #endregion

        #region Fields
        internal TranslateTransform _translate;
        private Size _extent = new Size(0, 0), _viewport = new Size(0, 0), 
            infiniteSize=new Size(double.PositiveInfinity, double.PositiveInfinity),
            measureSize=new Size();
        private Point emptyPoint = new Point(0,0), offset = new Point(0, 0);
        private Rect arrangeRect = new Rect();

        private ScrollViewer scrollViewer;
        private bool canHScroll = false, canVScroll = false;
        internal List<RibbonTabItemModel> TabItemModels = new List<RibbonTabItemModel>();
        
        #endregion

        #region IRibbonControl Implementation

        /// <summary>
        /// Gets a boolean value indicating whether the contol's size is large
        /// </summary>
        public bool IsLarge
        {
            get { return true; }
        }

        #endregion
    }
}
